package org.asiainfo.flowable.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.asiainfo.common.core.constant.TaskConstants;
import org.asiainfo.common.core.exception.ServiceException;
import org.asiainfo.common.core.utils.SpringUtils;
import org.asiainfo.common.core.utils.StringUtils;
import org.asiainfo.common.flowable.factory.FlowServiceFactory;
import org.asiainfo.common.json.utils.JsonUtils;
import org.asiainfo.flowable.domain.bo.WfTaskBo;
import org.asiainfo.flowable.domain.vo.WfFormVo;
import org.asiainfo.flowable.domain.vo.WfTaskVo;
import org.asiainfo.flowable.service.WfDeployFormService;
import org.asiainfo.flowable.service.WfInstanceService;
import org.asiainfo.system.api.RemoteDeptService;
import org.asiainfo.system.api.RemoteRoleService;
import org.asiainfo.system.api.RemoteUserService;
import org.asiainfo.system.api.domain.vo.RemoteDeptVo;
import org.asiainfo.system.api.domain.vo.RemoteRoleVo;
import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.identitylink.api.history.HistoricIdentityLink;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 流程实例管理服务实现类
 *
 * @author dotor-ww
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class WfInstanceServiceImpl extends FlowServiceFactory implements WfInstanceService {

    @DubboReference
    private RemoteUserService remoteUserService;

    @DubboReference
    private RemoteRoleService remoteRoleService;

    @DubboReference
    private RemoteDeptService remoteDeptService;

    /**
     * 激活/挂起流程实例
     *
     * @param instanceId   流程实例ID
     * @param suspendState 1-激活，2-挂起
     */
    @Override
    public void updateState(String instanceId, Integer suspendState) {
        // 1.激活流程
        if (SuspensionState.ACTIVE.getStateCode() == suspendState) {
            runtimeService.activateProcessInstanceById(instanceId);
        }
        // 2.挂起流程
        if (SuspensionState.SUSPENDED.getStateCode() == suspendState) {
            runtimeService.suspendProcessInstanceById(instanceId);
        }
    }

    /**
     * 终止流程实例
     *
     * @param wfTaskBo 流程任务业务对象
     */
    @Override
    public void stopProcessInstance(WfTaskBo wfTaskBo) {

    }

    /**
     * 删除流程实例
     *
     * @param instanceId 流程实例ID
     * @param reason     删除原因
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteProcessInstance(String instanceId, String reason) {
        // 1.查询历史流程
        HistoricProcessInstance historicProcessInstance = historyService
            .createHistoricProcessInstanceQuery()
            .processInstanceId(instanceId)
            .singleResult();

        if (ObjectUtil.isNull(historicProcessInstance)) {
            throw new ServiceException("流程实例不存在:" + instanceId);
        }
        // 2.判断结束时间不为空
        if (ObjectUtil.isNotNull(historicProcessInstance.getEndTime())) {
            // 3.删除历史流程
            historyService.deleteHistoricProcessInstance(historicProcessInstance.getId());
            return;
        }
        // 4.删除流程是咧
        runtimeService.deleteProcessInstance(instanceId, reason);
        // 5.删除历史流程
        historyService.deleteHistoricProcessInstance(instanceId);
    }

    /**
     * 流程实例详情
     *
     * @param procInsId 流程实例ID
     * @param deployId  流程部署ID
     * @return 流程实例详情
     */
    @Override
    public Dict queryProcessDetail(String procInsId, String deployId) {
        Dict dict = new Dict();
        if (StringUtils.isNotBlank(procInsId)) {
            List<HistoricTaskInstance> taskInstanceList = historyService
                .createHistoricTaskInstanceQuery()
                .processInstanceId(procInsId)
                .orderByHistoricTaskInstanceStartTime()
                .desc()
                .list();

            List<WfTaskVo> wfTaskVoList = new ArrayList<>();
            List<Comment> commentList = taskService.getProcessInstanceComments(procInsId);
            for (HistoricTaskInstance taskInstance : taskInstanceList) {
                WfTaskVo wfTaskVo = buildWfTaskVo(taskInstance);
                List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(taskInstance.getId());
                String approvalInfo = handleApprovalInfo(linksForTask);
                if(StringUtils.isNotBlank(approvalInfo)){
                    wfTaskVo.setCandidate(approvalInfo.substring(0, approvalInfo.length() - 1));
                }
                if(ObjectUtil.isNotNull(taskInstance.getDurationInMillis())){
                    wfTaskVo.setDuration(DateUtil.formatBetween(taskInstance.getDurationInMillis(), BetweenFormatter.Level.SECOND));
                }
                if(CollUtil.isNotEmpty(commentList)){
                    List<Comment> comments = commentList.stream().filter(c -> c.getTaskId().equals(taskInstance.getId())).toList();
                    wfTaskVo.setCommentList(comments);
                }
                wfTaskVoList.add(wfTaskVo);
            }
            dict.put("flowList", wfTaskVoList);
        }
        // 第一次申请获取初始化表单
        if (StringUtils.isNotBlank(deployId)) {
            WfFormVo wfFormVo = SpringUtils.getBean(WfDeployFormService.class).queryFormByDeployId(deployId);
            if (ObjectUtil.isNull(wfFormVo)) {
                throw new ServiceException("请先配置流程表单");
            }
            dict.put("rule", JsonUtils.parseObject(wfFormVo.getRule(), Map.class));
            dict.put("option", JsonUtils.parseObject(wfFormVo.getOptions(), Map.class));

        }
        return dict;
    }

    /**
     * 处理人员审批信息
     *
     * @param linksForTask 审批人列表
     * @return 审批信息
     */
    private String handleApprovalInfo(List<HistoricIdentityLink> linksForTask) {
        StringBuilder approvalInfo = new StringBuilder();
        for (HistoricIdentityLink identityLink : linksForTask) {
            // 1.候选人
            if ("candidate".equals(identityLink.getType())) {
                // 2.获取候选人用户信息
                if (StringUtils.isNotBlank(identityLink.getUserId())) {
                    Long userId = Convert.toLong(identityLink.getUserId());
                    String nickName = remoteUserService.getUserInfoById(userId).getNickName();
                    approvalInfo.append(nickName).append(",");
                }
                // 3.获取候选人组信息
                if (StringUtils.isNotBlank(identityLink.getGroupId())) {

                    if (identityLink.getGroupId().startsWith(TaskConstants.ROLE_GROUP_PREFIX)) {
                        // 4.是否是角色
                        Long roleId = Convert.toLong(StringUtils.stripStart(identityLink.getGroupId(), TaskConstants.ROLE_GROUP_PREFIX));
                        RemoteRoleVo remoteRoleVo = remoteRoleService.selectRemoteRoleByRoleId(roleId);
                        approvalInfo.append(remoteRoleVo.getRoleName()).append(",");

                    } else if (identityLink.getGroupId().startsWith(TaskConstants.DEPT_GROUP_PREFIX)) {
                        // 5.是否是部门
                        Long deptId = Convert.toLong(StringUtils.stripStart(identityLink.getGroupId(), TaskConstants.DEPT_GROUP_PREFIX));
                        RemoteDeptVo remoteDeptVo = remoteDeptService.selectDeptById(deptId);
                        approvalInfo.append(remoteDeptVo.getDeptName()).append(",");
                    }
                }
            }
        }
        return approvalInfo.toString();
    }

    /**
     * 构建流程任务信息
     *
     * @param taskInstance 历史任务实例
     * @return 流程任务信息
     */
    private WfTaskVo buildWfTaskVo(HistoricTaskInstance taskInstance) {
        WfTaskVo wfTaskVo = new WfTaskVo();
        wfTaskVo.setProcDefId(taskInstance.getProcessDefinitionId());
        wfTaskVo.setTaskId(taskInstance.getId());
        wfTaskVo.setTaskDefKey(taskInstance.getTaskDefinitionKey());
        wfTaskVo.setTaskName(taskInstance.getName());
        wfTaskVo.setCreateTime(taskInstance.getCreateTime());
        wfTaskVo.setFinishTime(taskInstance.getEndTime());
        if (StringUtils.isNotBlank(taskInstance.getAssignee())) {
            Long userId = Convert.toLong(taskInstance.getAssignee());
            String nickName = remoteUserService.getUserInfo(userId, null).getNickname();
            wfTaskVo.setAssigneeName(nickName);
            wfTaskVo.setAssigneeId(userId);
        }
        return wfTaskVo;
    }
}
